package thinkingInJava.concurrency;
//: concurrency/E26_Restaurant2.java
/********************** Exercise 26 ***********************
 * Add a BusBoy class to Restaurant.java. After the meal is
 * delivered, the WaitPerson should notify the BusBoy to
 * clean up.
 *********************************************************/
import java.util.concurrent.*;
import static thinkingInJava.YTool.YPrint.*;
class WaitPerson3 implements Runnable {
	private RestaurantT restaurant;
	boolean notified;
	public WaitPerson3(RestaurantT r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized(this) {
					while(restaurant.meal == null)
						wait(); // ... for the chef to produce a meal
				}
				print("Waitperson got " + restaurant.meal);
				synchronized(restaurant.busBoy) {
					restaurant.busBoy.notified = true;
					restaurant.busBoy.meal = restaurant.meal;
					restaurant.busBoy.notifyAll(); // Clean up
				}
				synchronized(restaurant.chef) {
					restaurant.meal = null;
					restaurant.chef.notifyAll(); // Ready for another
				}
				synchronized(this) {
					if(!notified)
						wait(); // ... for the bus boy to clean up
					notified = false;
				}
			}
		} catch(InterruptedException e) {
			print("WaitPerson interrupted");
		}
	}
}
class BusBoy implements Runnable {
	private RestaurantT restaurant;
	boolean notified;
	volatile Meal2 meal;
	public BusBoy(RestaurantT r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized(this) {
					if(!notified)
						wait(); // ... for meal delivery
					notified = false;
				}
				print("Busboy cleaned up " + meal);
				synchronized(restaurant.waitPerson) {
					restaurant.waitPerson.notified = true;
					restaurant.waitPerson.notifyAll();
				}
			}
		} catch(InterruptedException e) {
			print("BusBoy interrupted");
		}
	}
}
class Chef2 implements Runnable {
	private RestaurantT restaurant;
	private int count = 0;
	public Chef2(RestaurantT r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				synchronized(this) {
					while(restaurant.meal != null)
						wait(); // ... for the meal to be taken
				}
				if(++count == 10) {
					print("Out of food, closing");
					restaurant.exec.shutdownNow();
				}
				printnb("Order up! ");
				synchronized(restaurant.waitPerson) {
					restaurant.meal = new Meal2(count);
					restaurant.waitPerson.notifyAll();
				}
				TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch(InterruptedException e) {
			print("Chef interrupted");
		}
	}
}
class RestaurantT {
	Meal2 meal;
	ExecutorService exec = Executors.newCachedThreadPool();
	WaitPerson3 waitPerson = new WaitPerson3(this);
	BusBoy busBoy = new BusBoy(this);
	Chef2 chef = new Chef2(this);
	public RestaurantT() {
		exec.execute(chef);
		exec.execute(waitPerson);
		exec.execute(busBoy);
	}
}
public class Restaurant3 {
	public static void main(String[] args) {
		new RestaurantT();
	}
} /* Output: (Sample)
Order up! Waitperson got Meal2 1
Busboy cleaned up Meal2 1
Order up! Waitperson got Meal2 2
Busboy cleaned up Meal2 2
Order up! Waitperson got Meal2 3
Busboy cleaned up Meal2 3
Order up! Waitperson got Meal2 4
Busboy cleaned up Meal2 4
Order up! Waitperson got Meal2 5
Busboy cleaned up Meal2 5
Order up! Waitperson got Meal2 6
Busboy cleaned up Meal2 6
Order up! Waitperson got Meal2 7
Busboy cleaned up Meal2 7
Order up! Waitperson got Meal2 8
Busboy cleaned up Meal2 8
Order up! Waitperson got Meal2 9
Busboy cleaned up Meal2 9
Out of food, closing
WaitPerson interrupted
BusBoy interrupted
Order up! Chef interrupted
 *///:~
//The waitperson notifies the busboy and the chef in parallel, so meal preparation
//and clean up are simultaneous. We use the notified field in the BusBoy and
//WaitPerson classes; without this flag, a missed signal may stall the program. It
//is vital that you understand how these entities communicate with each other,
//and the various scenarios that you encounter in concurrent programs.
